package com.apache.passport.common;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * description: Salt MD5 加强模块<br>
 * 提供 16 位与 32 位 MD5 加密与其 Salt 加密功能<p>
 * Salt 加密方法调用：<br>
 * MD5 md5 = new MD5();<br>
 * String [] _tmp = MD5.getInstance().salt32("密文"); <br>
 * System.out.println(_tmp[0] + "\t" + _tmp[1]);<br>
 * MD5.getInstance().cell16("密文");<br>
 * 原理:相当于对md5加密后的数据进行二次md5加密,且只取从第8位到24位的值<br>
 *
 * @author Hou Dayu 创建时间：2016-5-14
 */
public class SaltEncrypt {

    private SaltEncrypt() {
        //SaltEncrypt
    }

    private static SaltEncrypt instance;

    public static SaltEncrypt getInstance() {
        if (null == instance) {
            instance = new SaltEncrypt();
        }
        return instance;
    }

    //随机密钥长度
    private static final int _KEYTLENGTH = 6;

    /**
     * description:  生成随机密钥
     *
     * @param length 密钥长度
     * @return
     */
    private String getRandomKeyt(int length) throws Exception {
        if (length < 1)
            throw new Exception("密钥长度不能小于 1");
        String _keyt = "";
        for (int i = 0; i < length; i++) {
            _keyt += (char) (33 + (int) (Math.random() * (126 - 33 + 1)));
        }
        return _keyt;
    }

    /**
     * description:   32位标准 MD5 加密
     *
     * @return 密文 返回 Null 值则出现异常
     */
    public String cell32(String plainText) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();
            int i;
            StringBuilder buf = new StringBuilder("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            return buf.toString();// 32位的加密

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * description:  32 位 salt 加密
     *
     * @param plainText 明文
     * @return 索引 0 是密文，索引 1 是二次密钥
     */
    public String[] salt32(String plainText) throws Exception {
        return salt("cell32", plainText);
    }

    /**
     * description:  16 位标准 MD5 加密
     *
     * @param plainText 明文
     * @return 密文<br> 返回 Null 值则出现异常
     */
    public String cell16(String plainText) {
        String result = cell32(plainText);
        if (result == null)
            return null;
        return result.toString().substring(8, 24);// 16位的加密
    }

    /**
     * description:  16 位 salt 加密
     *
     * @param plainText 明文
     * @return 索引 0 是密文，索引 1 是二次密钥
     */
    public String[] salt16(String plainText) throws Exception {
        return salt("cell16", plainText);
    }

    /**
     * description:  根据调用的方法名称执行不同的方法
     *
     * @param saltFunctionName 加密的方法名称
     * @param plainText
     * @return
     */
    private String[] salt(String saltFunctionName, String plainText) throws Exception {
        String _keyt = getRandomKeyt(_KEYTLENGTH);
        return new String[] { (String) this.getClass()
                .getMethod(saltFunctionName, Class.forName("java.lang.String"))
                .invoke(this, (cell32(plainText) + _keyt)), _keyt };
    }
}